package com.ruoyi.business.service.impl;

import com.ruoyi.business.service.IProcessService;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.sql.BatchUpdateException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

@Service
public class IProcessServiceImpl implements IProcessService {
    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;
    @Override
    public Deployment deploy(String filePath) throws FileNotFoundException {
        Deployment deployment = null;
        //文件类型
        String extension = FilenameUtils.getExtension(filePath);
        FileInputStream fileInputStream = new FileInputStream(filePath);
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
        if ("zip".equals(extension)){
            //包装流转换
            ZipInputStream zipInputStream = new ZipInputStream(fileInputStream);
            //部署文件获得部署应用的对象
            deployment = deploymentBuilder.addZipInputStream(zipInputStream).deploy();
        }else{
            deployment = deploymentBuilder.addInputStream(filePath, fileInputStream).deploy();
        }
        return deployment;
    }

    @Override
    public ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId) {
        //根据部署对象Id获取到流程定义对象
        return repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
    }

    @Override
    public InputStream getFileAsXMLAsStreamByDeploymentId(Long deploymentId) {
        //转换deploymentId数据类型
        String deploymentIdStr = deploymentId.toString();
        //根据部署Id获取流程定义对象,调用本类中的方法获取
        //ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentIdStr).singleResult();
        ProcessDefinition processDefinition = this.getProcessDefinitionByDeploymentId(deploymentIdStr);
        return repositoryService.getResourceAsStream(deploymentIdStr, processDefinition.getResourceName());
    }

    @Override
    public InputStream GenerateImgAsStreamByDeploymentId(Long deploymentId) {

        //获取流程定义对象
        ProcessDefinition processDefinition = this.getProcessDefinitionByDeploymentId(deploymentId.toString());
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        return getImgInputStream(bpmnModel,Collections.emptyList(), Collections.emptyList());
    }

    private InputStream getImgInputStream(BpmnModel bpmnModel,List<String> highLightActivities, List<String> highLightFlows ) {
        ProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
        return generator.generateDiagram(bpmnModel,
                highLightActivities,
                highLightFlows,
                "宋体",
                "宋体",
                "宋体"
        );
    }

    @Override
    public ProcessInstance startProcessDefinition(String definitionKey, String businessKey, HashMap<String, Object> map) {
        return runtimeService.startProcessInstanceByKey(definitionKey,businessKey,map);
    }


    @Override
    public List<Task> getTaskByInstanceId(String id) {
        return taskService.createTaskQuery()
                .processInstanceId(id)
                .list();
    }

    @Override
    public void setTaskCandidateUser(String taskId, String userId) {
        taskService.addCandidateUser(taskId,userId);
    }

    @Override
    public InputStream GenerateImgAsStreamByInstanceId(Long instanceId) {
        ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId.toString()).singleResult();
        if (instance == null){
            throw new BusinessException("流程实例不存在");
        }
        BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
        List<String> activeActivityIds = runtimeService.getActiveActivityIds(String.valueOf(instanceId));
        return getImgInputStream(bpmnModel,activeActivityIds,Collections.emptyList());
    }

    @Override
    public void deleteProcessInstance(String instanceId, String reason) {
        runtimeService.deleteProcessInstance(instanceId, reason);
    }

    @Override
    public List<Task> getTaskListByDefinitionKeyAndUserId(String definitionKey, String userId, int startIndex, Integer pageSize) {
        return taskService.createTaskQuery()//创建一个任务查询对象
                .processDefinitionKey(definitionKey)//条件过滤,查询指定流程实例
                .taskCandidateOrAssigned(userId)//查询指定任务负责人
                .orderByTaskCreateTime()//根据创建时间排序
                .asc()
                .listPage(startIndex, pageSize);
    }
    @Override
    public long getTaskCountByDefinitionKeyAndUserId(String definitionKey, String userId) {
        return taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)//条件过滤,查询指定流程实例
                .taskCandidateOrAssigned(userId)//查询指定任务负责人
                .count();
    }

    @Override
    public ProcessInstance getProcessInstanceById(String processInstanceId) {
        return runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
    }

    @Override
    public Task getTaskById(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }

    @Override
    public void claimAndCompleteTask(Task task, boolean auditStatus, String comment) {
        //领取任务
        taskService.claim(task.getId(), ShiroUtils.getUserId().toString());
        String commentStr = auditStatus?"【同意】":"【拒绝】";
        if(StringUtils.isNotEmpty(comment)){
            commentStr +=comment;
        }
        //添加任务批注
        taskService.addComment(task.getId(),task.getProcessInstanceId(),commentStr + comment);
        //完成任务
        Map<String ,Object> variables = new HashMap<>();
        variables.put(task.getTaskDefinitionKey(), auditStatus);
        taskService.setVariables(task.getId(),variables);
        taskService.complete(task.getId());
    }

    @Override
    public void claimAndCompleteTask(String taskId, Map<String, Object> variables, String comment) {
        //获取任务对象
        Task task = this.getTaskById(taskId);
        //添加批注
        this.addTaskComment(taskId, task.getProcessInstanceId() ,comment);
        //覆盖流程变量
        this.setVariables(taskId,variables);
        //完成任务
        taskService.complete(taskId);
    }

    @Override
    public void addTaskComment(String taskId, String instanceId, String comment) {
        taskService.addComment(taskId, instanceId, comment);
    }

    @Override
    public void setVariables(String taskId, Map<String, Object> variables) {
        taskService.setVariables(taskId, variables);
    }

    @Override
    public long selectDoneTaskCount(String definitionKey, String userId) {
        return historyService
                .createHistoricTaskInstanceQuery()
                .processDefinitionKey(definitionKey)
                .taskAssignee(userId)
                .finished()
                .count();
    }
    @Override
    public List<HistoricTaskInstance> selectDoneTaskList(String definitionKey, String userId, Integer firstResult, Integer pageSize) {
        return historyService
                .createHistoricTaskInstanceQuery()
                .processDefinitionKey(definitionKey)
                .taskAssignee(userId)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .listPage(firstResult,pageSize);
    }
    @Override
    public HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId) {
        return historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
    }

    @Override
    public List<HistoricActivityInstance> selectHistoryList(String instanceId) {
        return historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .activityType("userTask")
                .finished()
                .orderByHistoricActivityInstanceEndTime()
                .asc().list();
    }

    @Override
    public String selectHistoryTaskCommentByTaskId(String taskId) {
        List<Comment> taskComments = taskService.getTaskComments(taskId);
        if (CollectionUtils.isEmpty(taskComments)){
            return " ";
        }
        return taskComments.get(0).getFullMessage();
    }
}
